package com.healthdata.service.impl;

import com.healthdata.service.CalculateService;
import com.healthdata.service.PaintService;
import com.healthdata.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import weka.core.Instances;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

@Service
public class PaintServiceImpl implements PaintService {

    @Autowired
    private CalculateService calculateService;

    //直方图数据
    public HistogramVO generateHistogram(double[] data){
        HistogramVO histogramVO=new HistogramVO();

        double min = Arrays.stream(data).min().getAsDouble();
        double max = Arrays.stream(data).max().getAsDouble();

        // 使用Sturges公式计算分组数
        int numBins = (int) Math.ceil(1 + 3.322 * Math.log(data.length));
        double binWidth = (max - min) / numBins;

        // 计算每组频数
        int[] binCounts = new int[numBins];
        for (double value : data) {
            int binIndex = Math.min((int) ((value - min) / binWidth), numBins - 1);
            binCounts[binIndex]++;
        }

        // 构建直方图数据
        ArrayList<Double> xAxis = new ArrayList<>();
        ArrayList<Integer> yAxis = new ArrayList<>();

        for (int i = 0; i < numBins; i++) {
            double binCenter = min + i * binWidth + binWidth / 2;
            xAxis.add(binCenter);
            yAxis.add(binCounts[i]);
        }

        histogramVO.setType("bar");
        histogramVO.setName("直方图数据分布");
        histogramVO.setXAxis(xAxis);
        histogramVO.setYAxis(yAxis);
        return histogramVO;
    }

    //直方图上叠加的分布曲线数据
    public CurveVO generateCurve(double[] data, HistogramVO histogram) {

        CurveVO curveVO=new CurveVO();

        double mean = calculateService.mean(data);
        double stdDev = calculateService.deviation(data);

        @SuppressWarnings("unchecked")
        ArrayList<Double> xValues = histogram.getXAxis();

        double min = xValues.get(0) - (xValues.get(1) - xValues.get(0)) * 2;
        double max = xValues.get(xValues.size() - 1) + (xValues.get(1) - xValues.get(0)) * 2;

        // 生成更密集的曲线点
        ArrayList<Double> curveX = new ArrayList<>();
        ArrayList<Double> curveY = new ArrayList<>();

        int points = 100;
        for (int i = 0; i <= points; i++) {
            double x = min + (max - min) * i / points;
            curveX.add(x);

            // 正态分布概率密度函数
            double y = (1.0 / (stdDev * Math.sqrt(2 * Math.PI))) *
                    Math.exp(-Math.pow(x - mean, 2) / (2 * Math.pow(stdDev, 2)));

            // 缩放曲线使其与直方图在视觉上匹配
            double maxCount = Collections.max((histogram.getYAxis()));
            double scalingFactor = maxCount / getNormalDistributionPeak(stdDev);
            curveY.add(y * scalingFactor);
        }


        curveVO.setType("line");
        curveVO.setName("分布曲线图");
        curveVO.setCurveX(curveX);
        curveVO.setCurveY(curveY);

        return curveVO;
    }

    // 获取正态分布的峰值
    private double getNormalDistributionPeak(double stdDev) {
        return (1.0 / (stdDev * Math.sqrt(2 * Math.PI)));
    }


    // 生成箱线图
    public BoxPlotVO generateBoxPlot(double[] data) {
        BoxPlotVO boxPlotVO=new BoxPlotVO();
        Arrays.sort(data);

        // 计算 Min 和 Max
        boxPlotVO.setMin(data[0]);
        boxPlotVO.setMax(data[data.length - 1]);

        // 计算 Q1, Median, Q3
        boxPlotVO.setQ1(calculatePercentile(data, 25));
        boxPlotVO.setMedian(calculatePercentile(data, 50));
        boxPlotVO.setQ3(calculatePercentile(data, 75));

        return boxPlotVO;
    }

    // 计算百分位数
    private double calculatePercentile(double[] data, int percentile) {
        int index = (int) Math.ceil(percentile / 100.0 * data.length) - 1;
        return data[index];
    }

}
